package gui;

import gui.FileTransfer.FileTransferDialog;
import gui.FileTransfer.FileTransferPanel;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.text.*;
import javax.swing.event.*;

import client.libmessenger.*;
import common.Constants;

public class MessengerWindow extends JFrame implements WindowListener, ActionListener, ComponentListener
{	
	// data structures
	public static MessengerWindow instance = null;
	protected LibMessenger libMessage = null;
	protected MSNListenerImpl listener = new MSNListenerImpl();
	protected String username = null;
	
	protected ArrayList<Contact> contacts = new ArrayList<Contact>();
	protected ArrayList<ConversationWindow> conversations = new ArrayList<ConversationWindow>();
	protected ArrayList<TicTacToeWindow> TTTwindows = new ArrayList<TicTacToeWindow>();
	protected FileTransferDialog fileTransferDialog = new FileTransferDialog(this);		
	
	private boolean groupFlag;
	
	// Interface elements    
	protected JList lstOnlineUsers = null;
	protected JList lstOfflineUsers = null;
	protected JComboBox cboOnlineStatus = null;
        
	JMenuItem mnuFile_SendMessage;
	JMenuItem mnuFile_SendFile;
	JMenuItem mnuFile_PlayTTT;
	JMenuItem mnuFile_Logout;
	JMenuItem mnuFile_Quit;
	
	JMenuItem mnuContact_Add;	
	JMenuItem mnuContact_Remove;
	JMenuItem mnuContact_ToggleBlock;
	JMenuItem mnuContact_Assign;
	JMenuItem mnuContact_Search;
	
	private JTree listContactTree;
	private DefaultMutableTreeNode top;
	private DefaultTreeModel model;
	private JScrollPane treeView;
	private Container container;
	private GridBagLayout gridBagLayout;
	private GridBagConstraints constraints;
	private JPanel topPanel;
	private String[] statusString = {"Online", "Away", "Busy", "Offline"};
//	private String[] groupString;
	private ImageIcon onlineIcon, offlineIcon, busyIcon, awayIcon; 
	
	
   public MessengerWindow(LibMessenger lm, String username)
	{
    	this.instance = this;
    	this.username = username;
		this.libMessage = lm;
		this.libMessage.listener = this.listener;
		this.groupFlag = true;		
		// Set up the UI
		this.setTitle("~~ "+username+" ~~");			
		
		container = getContentPane();
		container.setLayout(new BorderLayout(5,5));		
		gridBagLayout = new GridBagLayout();
		constraints = new GridBagConstraints();        				
			
		cboOnlineStatus = new JComboBox(new String[] {"Offline", "Online", "Busy", "Away"});
		cboOnlineStatus.setSelectedIndex(Constants.ST_ONLINE);
		lstOnlineUsers = new JList(new String[]{});
		lstOfflineUsers = new JList(new String[]{});
		
		// Menu variables
		JMenuBar menubar = new JMenuBar();
		JMenu mnuFile = new JMenu("File");
		JMenu mnuContact = new JMenu("Contact");
		JMenu mnuHelp = new JMenu("Help");		
		
		mnuFile_SendMessage = new JMenuItem("Send a Message");
		mnuFile_SendMessage.addActionListener(this);		
		
		mnuFile_SendFile = new JMenuItem("Send a File");
		mnuFile_SendFile.addActionListener(this);
		
		mnuFile_PlayTTT = new JMenuItem("Play Tic Tac Toe");
		mnuFile_PlayTTT.addActionListener(this);
		
		mnuFile_Logout = new JMenuItem("Log out");
		mnuFile_Logout.addActionListener(this);
		
		mnuFile_Quit = new JMenuItem("Quit");
		mnuFile_Quit.addActionListener(this);
		
		
		mnuContact_Add = new JMenuItem("Add a contact...");
		mnuContact_Add.addActionListener(this);
		
		mnuContact_Remove = new JMenuItem("Delete contact");
		mnuContact_Remove.addActionListener(this);
		
		mnuContact_ToggleBlock = new JMenuItem("Toggle blocked");
		mnuContact_ToggleBlock.addActionListener(this);
		
		mnuContact_Search = new JMenuItem("Search by name...");
		mnuContact_Search.addActionListener(this);
		
		mnuContact_Assign = new JMenuItem("Assign Group");
		mnuContact_Assign.addActionListener(this);		
		
		JMenuItem mnuHelp_About = new JMenuItem("About...");
		mnuHelp_About.addActionListener(this);

		mnuFile.add(mnuFile_SendMessage);
		mnuFile.add(mnuFile_SendFile);
		mnuFile.add(mnuFile_PlayTTT);
		mnuFile.addSeparator();
		mnuFile.add(mnuFile_Logout);
		mnuFile.add(mnuFile_Quit);
		mnuContact.add(mnuContact_Add);
		mnuContact.add(mnuContact_Remove);
		mnuContact.add(mnuContact_ToggleBlock);
		mnuContact.add(mnuContact_Assign);
		mnuContact.add(mnuContact_Search);
		mnuHelp.add(mnuHelp_About);
		
		menubar.add(mnuFile);
		menubar.add(mnuContact);
		menubar.add(mnuHelp);
		
		this.setJMenuBar(menubar);		
		
		topPanel = new JPanel();
		topPanel.setLayout(gridBagLayout);
		
		JLabel lblCurrentStatus = new JLabel("Status    ");
		lblCurrentStatus.setHorizontalAlignment(JLabel.RIGHT);
		
		constraints.fill = GridBagConstraints.NONE;
		constraints.gridx = 0;
		constraints.gridy = 0;
		gridBagLayout.setConstraints(lblCurrentStatus, constraints);
		topPanel.add(lblCurrentStatus);
				
					
		// sort by group / status
		// search contact
		// logout
		// quit
		// group mgmt		
		
		cboOnlineStatus.setMaximumRowCount(4);
		cboOnlineStatus.addItemListener(new ItemListener(){
			public void itemStateChanged(ItemEvent e){
				cboOnlineStatusChange(e);
			}
		});
		
		constraints.fill = GridBagConstraints.BOTH;
		constraints.gridx = 1;
		constraints.gridy = 0;
		gridBagLayout.setConstraints(cboOnlineStatus, constraints);
		topPanel.add(cboOnlineStatus);
		
							
		// and now the nitty gritty itty bitty
		initDataStructures();
		reloadContactList();
		listContactTree = new JTree(top);
		model = (DefaultTreeModel)listContactTree.getModel();
		
		listContactTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		
		MouseListener ml = new MouseAdapter() {
		     public void mousePressed(MouseEvent e) {
		         if (e.getClickCount() >= 2) 
		        	 startConversation();
		     }
		};
		listContactTree.addMouseListener(ml);
		listContactTree.putClientProperty("JTree.lineStyle", "None");
		
		treeView = new JScrollPane(listContactTree);
		expandTree();
	//	ImageIcon leafIcon = createImageIcon("../Images/middle.gif");
	/*	if (leafIcon != null) {
		    DefaultTreeCellRenderer renderer = 
			new DefaultTreeCellRenderer();
		    renderer.setLeafIcon(leafIcon);
		    tree.setCellRenderer(renderer);
		}*/
		container.add(topPanel, BorderLayout.NORTH);
		container.add(treeView, BorderLayout.CENTER);	
		this.addWindowListener(this);
		addComponentListener(this);
		this.pack();
		this.setSize(300, 500);
	}
   
    public void 	windowClosed(WindowEvent e){}
    public void 	windowActivated(WindowEvent e){}
    public void 	windowClosing(WindowEvent e){this.mnuFile_QuitMouseClicked();}
    public void 	windowDeactivated(WindowEvent e) {}
    public void 	windowDeiconified(WindowEvent e) {}
    public void 	windowIconified(WindowEvent e) {}
    public void 	windowOpened(WindowEvent e) {}   
    public void componentMoved(ComponentEvent e) {}
    public void componentShown(ComponentEvent e) {}
    public void componentHidden(ComponentEvent e) {}
    public void componentResized(ComponentEvent e) {
        int width = getWidth();
        int height = getHeight();
        int minWidth = 300, minHeight = 500;
        
        boolean resize = false;
        if (width < minWidth) {
             resize = true;
             width = minWidth;
        }    
        if (height < minHeight) {
        	resize = true;
            height = minHeight;
        }
        if (resize)
            setSize(width, height);
     }
    
    private void startConversation(){
    	DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null){
   			JOptionPane.showMessageDialog(null, " You must select an online contact first!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   			return;
   		}
   		Object nodeInfo = node.getUserObject();
   		
   		if (node.isLeaf()){
   			String username = (String)nodeInfo;
   			if (username.lastIndexOf('(') != -1)
    			username = username.substring(0, username.lastIndexOf('(')-1);
   			boolean flag = true;
   			for (int i = 0; i < statusString.length; i++)
   				if (username.compareTo(statusString[i]) == 0)
   					flag = false;
    		if (flag){
    			DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)node.getParent();
    			String s = (String)node2.getUserObject();
    			if (s.compareTo(statusString[3]) != 0){
    				MessageFrame frame = getConversationWindow(username);
            		frame.setVisible(true);
            		frame.requestFocus();	
    			}    			
    		}    		  	
   		}
    }
   	
	protected void reloadTree(){
		model.setRoot(top);
		expandTree();
	}
	protected void reloadContactList()
	{
		top = new DefaultMutableTreeNode(username);	
		if (groupFlag){
			ArrayList<String> onlineContacts = new ArrayList<String>();
			ArrayList<String> offlineContacts = new ArrayList<String>();
			ArrayList<String> awayContacts = new ArrayList<String>();
			ArrayList<String> busyContacts = new ArrayList<String>();
			for(int i=0; i< contacts.size(); ++i){
				String contactString = "";
				
				if(contacts.get(i).groupName.length() > 0)
					contactString = contacts.get(i).name + " ("+contacts.get(i).groupName+"/"+Constants.STATUS_NAMES[contacts.get(i).status];
				else
					contactString = contacts.get(i).name + " ("+Constants.STATUS_NAMES[contacts.get(i).status];
			
				if(contacts.get(i).blocked)
					contactString += " BLOCKED";
				
				contactString += ")";
				
				switch(contacts.get(i).status){
					case Constants.ST_ONLINE:	onlineContacts.add(contactString);
												break;
					case Constants.ST_OFFLINE:	offlineContacts.add(contactString);
												break;
					case Constants.ST_AWAY:		awayContacts.add(contactString);
												break;
					case Constants.ST_BUSY:		busyContacts.add(contactString);
												break;
				  //case Constants.ST_BLOCK:	blockContacts.add(contactString);												
				}									
			} // for
			createTree(statusString[0], onlineContacts);
			createTree(statusString[1], awayContacts);
			createTree(statusString[2], busyContacts);
			createTree(statusString[3], offlineContacts);
			//createTree("Block", blockContacts, top);
		}
		else {
			
		}
	}
	private void createTree(String s, ArrayList<String> contactList){
		DefaultMutableTreeNode status = null, contact = null;
		status = new DefaultMutableTreeNode(s);
		top.add(status);
		for (int i = 0; i < contactList.size(); i++){
			contact = new DefaultMutableTreeNode(contactList.get(i));
			status.add(contact);
		}
		
	}
	private void expandTree(){
		int row = 0;
	    while (row++ < listContactTree.getRowCount()) {
	    	listContactTree.expandRow(row);
	      }
	}
	protected int getConversationWindowIndex(String destination)
	{
		for(int i=0; i<conversations.size(); ++i)
			if(conversations.get(i).destination.equals(destination))
				return i;
		
		return -1;
				
	}
	
	protected TicTacToeWindow searchTTTWindow(String opponent)
	{
		for(int i=0; i<TTTwindows.size(); ++i)
			if(TTTwindows.get(i).opponent.equals(opponent))
				return TTTwindows.get(i);
	
		return null;
	}
	
	protected TicTacToeWindow getTTTWindow(String opponent)
	{
		int index = -1;
		TicTacToeWindow result = null;
		
		for(int i=0; i<TTTwindows.size(); ++i)
			if(TTTwindows.get(i).opponent.equals(opponent))
			{
				index = i;
				break;
			} // IF
		
		if(index == -1)
		{
			result = new TicTacToeWindow(this.username, opponent);			
		} // IF
		else
		{
			result = TTTwindows.get(index);
		}
		
		result.setVisible(true);
		result.requestFocus();
		return result;
	}
	
	protected MessageFrame getConversationWindow(String destination)
	{
		int i = getConversationWindowIndex(destination);
		
		if(i != -1)
			return conversations.get(i).frame;
		else
		{		
			ConversationWindow newWindow = new ConversationWindow();
			newWindow.destination = new String(destination);			
			newWindow.frame = new MessageFrame(this.libMessage, new String(destination), new String(this.username));
			newWindow.frame.pack();
			newWindow.frame.setSize(500, 450);
			newWindow.frame.setVisible(true);
			conversations.add(newWindow);
			
			return newWindow.frame;
		} // ELSE
	}
	
	public void deregisterConversationWindow(String destination)
	{
		for(int i=0; i<conversations.size(); ++i)
		{
			if(conversations.get(i).destination.equals(destination))
			{
				conversations.remove(i);
				break;
			} // IF
		} // FOR
	}
	
	protected void initDataStructures()
	{
		for (int i=0; i<libMessage.initial_contacts.size(); ++i)
		{
			Contact newContact = new Contact();
			newContact.name = libMessage.initial_contacts.get(i);
			newContact.groupName = libMessage.initial_groups.get(i);
			newContact.status = libMessage.initial_statuses.get(i);
			newContact.blocked = libMessage.initial_blocked.get(i).booleanValue();
			
			this.contacts.add(newContact);
		} // FOR				
	}
	
	protected Contact getContactByName(String name)
	{
		for(int i=0; i<contacts.size(); ++i)
			if(contacts.get(i).name.equals(name))
				return contacts.get(i);
		
		return null;
	}
		
	public void uploadFileToUser(String destination)
	{      
      JFileChooser fileChooser = new JFileChooser();
      fileChooser.setDialogTitle("Select File To Transfer");
      fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
      fileChooser.setCurrentDirectory(new File ("."));
      
      if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
      {
      	String filename = fileChooser.getSelectedFile().getAbsolutePath();      	
      	this.libMessage.offerToSendFile(destination, filename);          	
      } // IF
		
	}
	
    public void actionPerformed(ActionEvent e)
    {
    	if(e.getSource() == mnuFile_Logout)
    		mnuFile_LogoutMouseClicked();
    	
    	else if(e.getSource() == mnuFile_Quit)
    		mnuFile_QuitMouseClicked();
    	    	
    	else if(e.getSource() == mnuFile_SendMessage)
    		mnuFile_SendMessageMouseClicked();
    	
    	else if(e.getSource() == mnuContact_Add)
    		mnuContact_AddMouseClicked();
    	
    	else if(e.getSource() == mnuContact_Remove)
    		mnuContact_RemoveMouseClicked();
    	
    	else if (e.getSource() == mnuContact_ToggleBlock)
    		mnuContact_ToggleBlockMouseClicked();
    	
    	else if(e.getSource() == mnuFile_SendFile)
    		mnuFile_SendFileMouseClicked();
    	
    	else if(e.getSource() == mnuFile_PlayTTT)
    		mnuFile_PlayTTTMouseClicked();
    	
    	else if (e.getSource() == mnuContact_Assign)
    		mnuContact_AssignMouseClicked();
    	
    	else if(e.getSource() == mnuContact_Search)
    		mnuContact_SearchMouseClicked();
    }
    
    public void mnuFile_PlayTTTMouseClicked()
    {

    	DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null){
   			JOptionPane.showMessageDialog(null, " You must select an online contact first!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   			return;
   		}
   		Object nodeInfo = node.getUserObject();
   	   	if (node.isLeaf()){
   	   		String selectedUsername = (String)nodeInfo;
   	   		if (selectedUsername.lastIndexOf('(') != -1)
   	   		   selectedUsername = selectedUsername.substring(0, selectedUsername.lastIndexOf('(')-1);
   	   		boolean flag = true;
   	   		for (int i = 0; i < statusString.length; i++)
   	   			if (selectedUsername.compareTo(statusString[i]) == 0)
   	   				flag = false;
   	   		if (flag){
   	   			DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)node.getParent();
   	   			String s = (String)node2.getUserObject();
   	   			if (s.compareTo(statusString[3]) != 0){
   	   				TicTacToeWindow TTT = new TicTacToeWindow(this.username, selectedUsername);
   	   				TTT.setVisible(true);
   	   				TTT.requestFocus();
   	    		
   	   				this.TTTwindows.add(TTT);
   	   				System.out.println(selectedUsername);
   	   				libMessage.initiateGame(selectedUsername, "TTT");
   	   			}
   	   		}   	   			
   		}   		
    }
    
    public void mnuFile_SendMessageMouseClicked() 
    {
    	DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null){
   			JOptionPane.showMessageDialog(null, " You must select an online contact first!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   			return;
   		}
   		Object nodeInfo = node.getUserObject();
   		
   		if (node.isLeaf()){
   			String username = (String)nodeInfo;
   			if (username.lastIndexOf('(') != -1)
    			username = username.substring(0, username.lastIndexOf('(')-1);
   			boolean flag = true;
   			for (int i = 0; i < statusString.length; i++)
   				if (username.compareTo(statusString[i]) == 0)
   					flag = false;
    		if (flag){
    			DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)node.getParent();
    			String s = (String)node2.getUserObject();
    			if (s.compareTo(statusString[3]) != 0){
    				MessageFrame frame = getConversationWindow(username);
       	   			frame.setVisible(true);
       	   			frame.requestFocus();    				
    			}    			
    		}    		  	
   		}    	    
    }
    
    public void mnuFile_SendFileMouseClicked() 
    {
    	DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null){
   			JOptionPane.showMessageDialog(null, " You must select an online contact first!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   			return;
   		}
   		Object nodeInfo = node.getUserObject();
   		
   		if (node.isLeaf()){
   			String username = (String)nodeInfo;
   			if (username.lastIndexOf('(') != -1)
    			username = username.substring(0, username.lastIndexOf('(')-1);
   			boolean flag = true;
   			for (int i = 0; i < statusString.length; i++)
   				if (username.compareTo(statusString[i]) == 0)
   					flag = false;
    		if (flag){
    			DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)node.getParent();
    			String s = (String)node2.getUserObject();
    			if (s.compareTo(statusString[3]) != 0){
    				this.uploadFileToUser(username);
    				
    			}    			
    		}    		  	
   		}
	 
    }
    
    public void mnuView_ByStatusMouseClicked( ) {
    	groupFlag = true;
    	reloadContactList();
    	reloadTree();
    	
    }
    public void mnuView_ByGroupsMouseClicked() {
    	groupFlag = false;
    	reloadContactList();
    	reloadTree();
    	
    }
    public void mnuContact_ToggleBlockMouseClicked() {
    	
   	 
   	 
    	DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null)
   			JOptionPane.showMessageDialog(null, " You must select a contact that you want to block!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   		else {
   			Object nodeInfo = node.getUserObject();
   	   		if (node.isLeaf()){
   	   			String username = (String)nodeInfo;
   	   			if (username.lastIndexOf('(') != -1)
   	   				username = username.substring(0, username.lastIndexOf('(')-1);
   	   			
   	   			boolean flag = true;
   	   			for (int i = 0; i < statusString.length; i++)
   	   				if (username.compareTo(statusString[i]) == 0)
   	   					flag = false;
   	   			if (flag){
   	   				DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)node.getParent();
   	   				String s = (String)node2.getUserObject();
   	   				
   	   				
   	   				//if (s.compareTo(statusString[3]) != 0){
   	   					// CALL FUNCTION TO BLOCK THE CONTACT
   	   					for(int ci=0; ci<this.contacts.size(); ++ci)
   	   						if(this.contacts.get(ci).name.equals(username))
   	   						{
   	   							boolean result = false;
   	   							
   	   							if(this.contacts.get(ci).blocked)
   	   								result = this.libMessage.unblockUser(username);
   	   							else
   	   								result = this.libMessage.blockUser(username);
   	   							
   	   							if(result)
   	   							{
   	   								this.contacts.get(ci).blocked = !this.contacts.get(ci).blocked;
   	   								reloadContactList();
   	   								reloadTree();
   	   							}
   	   							else
   	   								JOptionPane.showMessageDialog(null, "Toggle block failed: "+libMessage.lastError, "Error", JOptionPane.PLAIN_MESSAGE);
   	   							
   	   							break;
   	   						}
   	   				   	   					
   	   				//}
   	   				//else
   	   					//this.setTitle(s+"   @@@   "+statusString[3]);
   	   			}  			
   	   		}
   	   		else
   	   			JOptionPane.showMessageDialog(null, " You must select a contact that you want to block!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   		}
    }
    public void mnuContact_SearchMouseClicked() 
    {
			String regexp = JOptionPane.showInputDialog(null, "Enter a partial string to search for", "Regexp contact search", JOptionPane.PLAIN_MESSAGE);
			
			//if(regexp.indexOf('*') == -1)
				//regexp = "*"+regexp+"*";
			
			ArrayList results = libMessage.searchContacts(regexp);
			
			if(results.size() == 0)
				JOptionPane.showMessageDialog(null, "Your search did not return any matches", "snowballing is fun", JOptionPane.PLAIN_MESSAGE);
			else
				JOptionPane.showMessageDialog(null, "Matches:\n"+results.toString(), "Matches", JOptionPane.PLAIN_MESSAGE);
   	 
    }    
    
    public void mnuHelp_AboutMouseClicked() {
    	
    }        
    public void mnuContact_AssignMouseClicked(){
    	System.out.println("in add group");    	
    	DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null){
   			JOptionPane.showMessageDialog(null, " You must select an contact first!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   			return;
   		}
   		Object nodeInfo = node.getUserObject();
   		
   		if (node.isLeaf()){
   			String username = (String)nodeInfo;
   			if (username.lastIndexOf('(') != -1)
    			username = username.substring(0, username.lastIndexOf('(')-1);
   			boolean flag = true;
   			for (int i = 0; i < statusString.length; i++)
   				if (username.compareTo(statusString[i]) == 0)
   					flag = false;
   				if (flag){
    				String group = JOptionPane.showInputDialog(null, "Please enter the group that you want " + username + " to belong to", "Add group", JOptionPane.PLAIN_MESSAGE);
    				if(group == null) return;
    				
    				if (group.compareTo("") == 0)
    					JOptionPane.showMessageDialog(null, "You did not enter the group name", "No group name", JOptionPane.PLAIN_MESSAGE);
    				else {
    					if (libMessage.assignContactToGroup(username, group)){
    						getContactByName(username).groupName = new String(group);
    						JOptionPane.showMessageDialog(null, "Successfully add " + username + " to " + group, "Successfully Group Assignment", JOptionPane.PLAIN_MESSAGE);
    						reloadContactList();
    				    	reloadTree();
    					}
    					else
    						JOptionPane.showMessageDialog(null, "Unable to add " + username + " to " + group, "Group Assignment Failed", JOptionPane.PLAIN_MESSAGE);
    				}
    	    			
    		}    		  	
   		}
    }    
    public void mnuGroups_RenameMouseClicked() {}
    public void mnuGroups_DeleteMouseClicked() {}

    public void mnuFile_LogoutMouseClicked() 
    {    	
        if (libMessage.disconnect())
        {            
        	this.setVisible(false);
        	LoginWindow.instance.setVisible(true);
        }
        else
            JOptionPane.showMessageDialog(null, " Unable to log out, please try again later.", "Unable to Disconnect", JOptionPane.PLAIN_MESSAGE);
    }

    public void mnuFile_QuitMouseClicked()
    {
    	libMessage.disconnect();    
    	System.exit(0);
    }
    
    public void mnuContact_AddMouseClicked() 
    {
       String name = JOptionPane.showInputDialog(null, "Please enter the user of the contact that you want to add", "Add Contact", JOptionPane.PLAIN_MESSAGE);       
       
       if (name != null) {
      	 AddedContactInfo info = new AddedContactInfo();
      	 System.out.println("Adding contact "+name);
      	 
      	 if(libMessage.addContact(name, info))
      	 {
      		 System.out.println("Adding contact "+name+" whose status is "+info.status);
      		 Contact newContact = new Contact();
      		 newContact.groupName = "";
      		 newContact.name = new String(name);
      		 newContact.status = info.status;
      		 
      		 this.contacts.add(newContact);
      		 reloadContactList();
      		 reloadTree();
      	 } // IF
      	 else
      		 JOptionPane.showMessageDialog(null, name + " was NOT added to your contact list: "+libMessage.lastError, "Add Contact Failed", JOptionPane.ERROR_MESSAGE);
       }
    }

    public void mnuContact_RemoveMouseClicked() 
    { 
		
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) listContactTree.getLastSelectedPathComponent();
   		if (node == null){
   			JOptionPane.showMessageDialog(null, " You must select an online contact first!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
   			return;
   		}
   		Object nodeInfo = node.getUserObject();
   		
   		if (node.isLeaf()){
   			String username = (String)nodeInfo;
   			if (username.lastIndexOf('(') != -1)
    			username = username.substring(0, username.lastIndexOf('(')-1);
   			boolean flag = true;
   			for (int i = 0; i < statusString.length; i++)
   				if (username.compareTo(statusString[i]) == 0)
   					flag = false;
    		if (flag){
    			DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)node.getParent();
    			String s = (String)node2.getUserObject();
    			if (s.compareTo(statusString[3]) != 0){
    				if (libMessage.removeContact(username)){
    		   	   		this.contacts.remove(this.getContactByName(username));
    		   	   		reloadContactList();
    		   	   		reloadTree();
    		   	   	} // IF
    		   		else
    		   			JOptionPane.showMessageDialog(null, "Unable to remove contact: "+libMessage.lastError, "Warning", JOptionPane.ERROR_MESSAGE);
    				
    			}    			
    		}    		  	
   		}
   		else
   			JOptionPane.showMessageDialog(null, " You must select first a contact that you want to delete!", "No contact selected", JOptionPane.PLAIN_MESSAGE);
		
    }    
    
    public void cboOnlineStatusChange(ItemEvent e){
    	if (e.getStateChange()== ItemEvent.SELECTED){
    		// If we're going offline close all TTT windows
    		if(cboOnlineStatus.getSelectedIndex() == Constants.ST_OFFLINE)
    		{
    			for(int i=0; i<TTTwindows.size(); ++i)
    				TTTwindows.get(i).setVisible(false);
    		
    			TTTwindows.clear();
    		} // IF
    		
    		if (!libMessage.changeStatus(cboOnlineStatus.getSelectedIndex()))
                JOptionPane.showMessageDialog(null, "Unable to change your online status: "+libMessage.lastError, "Warning", JOptionPane.ERROR_MESSAGE);
    	}
    }
    
	class ConversationWindow
	{
		String destination;
		MessageFrame frame;
	}
	
	class Contact
	{
		String name;
		String groupName;
		int status;
		boolean blocked;
	}
	
    class MSNListenerImpl implements MSNListener
	{
		public void onClientChangeStatus(String username, int status) 
		{
			Contact client = getContactByName(username);
			
			if(client != null)
			{  
				// If the client is going offline and a TTT window is open, disable it and leave
				// a message
				
				if(status == Constants.ST_OFFLINE)
				{
					TicTacToeWindow tt = searchTTTWindow(username);
					
					if(tt != null)
					{
						tt.setEnabled(false);
						tt.setTitle(username + " has gone offline, this game is over");
						TTTwindows.remove(tt);
					}
				} // IF
				
				
				System.out.println("NOT NULL, username is " + username + " old status" + client.status + "  new status " + status);
				
				client.status = status;
				
				reloadContactList();
				reloadTree();
			} // IF
		}
		
		public void onReceiveMessage(String username, String message) 
		{
			MessageFrame frame = getConversationWindow(username);
			String conversation = frame.communicationPane.getText().replaceAll(frame.html, "").replaceAll(frame.head, "").replaceAll(frame.body,"").trim();
			frame.communicationPane.setText(conversation+" <p> "+username+" says: "+message);
			
			frame.setVisible(true);
			frame.requestFocus();			
			System.out.println("received msg from "+username+" "+message);
		}
		
		public void onFileTransferOffer(String username, String filename, String filesize) 
		{			
			String basename = filename.substring(filename.lastIndexOf(File.separatorChar)+1);						
			
			if (JOptionPane.showConfirmDialog(MessengerWindow.instance, "The user "+username+" is offering you the file "+basename+" ("+filesize+" bytes). Do you wish to receive it?", "File Receive Offer", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
			{
		      JFileChooser fileChooser = new JFileChooser();
		      fileChooser.setDialogTitle("Select Save Location");
		      fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		      fileChooser.setCurrentDirectory(new File ("."));
		      fileChooser.setSelectedFile(new File(basename));
		      
		      while(true)
		      {
			      if (fileChooser.showSaveDialog(MessengerWindow.instance) == JFileChooser.APPROVE_OPTION)
			      {			      				      	
			      	 if(!fileChooser.getSelectedFile().exists() || fileChooser.getSelectedFile().canWrite())
			      	 {			      		 
			      		 MessengerWindow.instance.fileTransferDialog.addFileTransferTask(basename, Integer.valueOf(filesize).intValue(), FileTransferPanel.TRANSFER_MODES.TM_DOWNLOAD);			      		 
			      		 MessengerWindow.instance.fileTransferDialog.setVisible(true);
			      		 //JOptionPane.showMessageDialog(MessengerWindow.instance, "Beginnging receive file of "+filename+" into "+fileChooser.getSelectedFile().getAbsolutePath());
			      		 if(!MessengerWindow.instance.libMessage.beginReceivingFile(username, filename, fileChooser.getSelectedFile().getAbsolutePath()))
			      			 JOptionPane.showMessageDialog(MessengerWindow.instance, "ERROR: file request failed: "+MessengerWindow.instance.libMessage.lastError);
			      		 
			      		 break;
			      	 }
			      	 else
			      		 JOptionPane.showMessageDialog(MessengerWindow.instance, "The selected file name cannot be written to", "I/O error", JOptionPane.ERROR_MESSAGE);
			      } // IF
			      else
			      	break;
		      } // WHILE
			} // IF
		}
		
		public void onFileSendStart(String username, String filename, int filesize)
		{
			String basename = filename.substring(filename.lastIndexOf(File.separatorChar)+1);
			MessengerWindow.instance.fileTransferDialog.addFileTransferTask(basename, filesize, FileTransferPanel.TRANSFER_MODES.TM_UPLOAD);
			MessengerWindow.instance.fileTransferDialog.setVisible(true);
		}
		
		public void onFileSendProgress(String destUserName, String filename, int fileSize, int bytesSent)
		{
			String basename = filename.substring(filename.lastIndexOf(File.separatorChar)+1);
			MessengerWindow.instance.fileTransferDialog.updateFileTransferTask(basename, bytesSent);
		}
		
		public void onFileReceiveProgress(String sourceUserName, String filename, int fileSize, int bytesReceived)
		{
			String basename = filename.substring(filename.lastIndexOf(File.separatorChar)+1);
			MessengerWindow.instance.fileTransferDialog.updateFileTransferTask(basename, bytesReceived);
		}
		
		// a client is starting a game with you
		public void onGameInitiation(String username, String gameName) 
		{
			System.out.println("game initiation, I'm "+MessengerWindow.instance.username+"  against "+username);
			
			if(gameName.equals("TTT"))
			{
				TicTacToeWindow TTT = new TicTacToeWindow(MessengerWindow.instance.username, username);
				TTT.setEnabled(false);
				TTTwindows.add(TTT);				
			}
		}
		
		// a client is sending you a move
		public void onGameMove(String username, String gameName, String move) 
		{
			System.out.println("game move, I'm "+MessengerWindow.instance.username+"  against "+username);
			
			if(gameName.equals("TTT"))
			{
				TicTacToeWindow TTT = getTTTWindow(username);
				TTT.setEnabled(true);
				TTT.recordOpponentTick(Integer.valueOf(move).intValue());
				TTT.setVisible(true);
				TTT.requestFocus();
			} // IF
		}		
	}

}
